/**
 * Copyright (c) 2009 Mujtaba Hassanpur.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import javax.imageio.ImageIO;
import javax.swing.*;

/**
 * Observes and displays the Bucket class.
 */
public class BucketView extends JPanel implements Observer
{
	private static final long serialVersionUID = 1L;
	private Bucket theBucket;
	private AffineTransform worldToND, ndToScreen;
	private boolean gridVisible = true;
	private BufferedImage imgGameOver;
	private BufferedImage imgPaused;
	private BufferedImage imgLogo1;
	private BufferedImage imgGameLogo;
	
	public BucketView(Bucket inBucket)
	{
		theBucket = inBucket;
		worldToND = new AffineTransform();
		ndToScreen = new AffineTransform();
		
		// try to load images
		imgGameOver = null;
		try
		{
			imgGameOver = ImageIO.read(new File("images/gameover.gif"));
		}
		catch(IOException e) { }
		
		imgPaused = null;
		try
		{
			imgPaused = ImageIO.read(new File("images/paused.gif"));
		}
		catch(IOException e) { }
		
		imgLogo1 = null;
		try
		{
			imgLogo1 = ImageIO.read(new File("images/roundededge.gif"));
		}
		catch(IOException e) { }
		
		imgGameLogo = null;
		try
		{
			imgGameLogo = ImageIO.read(new File("images/brick_rain.gif"));
		}
		catch(IOException e) { }
	}
	
	/**
	 * Calculate the transform for World coordinates to Normalized Device.
	 */
	public void calculateWorldToND(double windowTop, double windowBottom, double windowLeft, double windowRight)
	{
		worldToND.setToIdentity();
		worldToND.translate(-windowLeft, -windowBottom);
		worldToND.scale(1.0/((double)(windowRight - windowLeft)), 1.0/((double)(windowTop - windowBottom)));
	}
	
	/**
	 * Calculate the transform for Normalized Device to Screen Coordinates.
	 */
	public void calculateNDToScreen()
	{
		ndToScreen.setToIdentity();
		ndToScreen.scale(this.getWidth(), -this.getHeight());
		ndToScreen.translate(0, -this.getHeight());
		ndToScreen.translate(0, (this.getHeight() - CollapsingBricksGame.getCollapsingBricksGame().getViewingWindowTop()));
	}
	
	public void update(Observable arg0, Object arg1)
	{
		repaint();
	}
	
	public void paintComponent(Graphics g)
	{
		// draw all objects in the bucket
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D)g;
		
		// save the transform
		AffineTransform saveAT = g2.getTransform();
		Color saveColor = g2.getColor();
		
		CollapsingBricksGame.GameState gameState = CollapsingBricksGame.getCollapsingBricksGame().getGameState();
		
		if(gameState == CollapsingBricksGame.GameState.LOGO1)
		{
			/*
			 * Draw our logo, shown when the game first loads.
			 */
			
			g.setColor(Color.black);
			g.fillRect(0, 0, this.getWidth(), this.getHeight());
			
			if(imgLogo1 == null)
			{
				// can't find logo...
			}
			else
			{
				g.drawImage(imgLogo1, (this.getWidth() - imgLogo1.getWidth())/2, (this.getHeight() - imgLogo1.getHeight())/2, null);
			}
		}
		else if(gameState == CollapsingBricksGame.GameState.MENU)
		{
			/*
			 * Draw our logo, shown when the game first loads.
			 */
			
			g.setColor(Color.black);
			g.fillRect(0, 0, this.getWidth(), this.getHeight());
			
			if(imgGameLogo == null)
			{
				// can't find logo...
			}
			else
			{
				g.drawImage(imgGameLogo, (this.getWidth() - imgGameLogo.getWidth())/2, 0, null);
			}
		}
		else if(gameState == CollapsingBricksGame.GameState.GAME_OVER)
		{
			/*
			 * Simply draw a black background with a centered text that states
			 * "GAME OVER". Use the anti-aliased text image, if possible.
			 * Otherwise just write it using a system font.
			 */
			
			g.setColor(Color.black);
			g.fillRect(0, 0, this.getWidth(), this.getHeight());
			
			if(imgGameLogo == null)
			{
				// can't find logo...
			}
			else
			{
				g.drawImage(imgGameLogo, (this.getWidth() - imgGameLogo.getWidth())/2, 0, null);
			}
			
			if(imgGameOver == null) // text version
			{
				g.setColor(Color.white);
				g.setFont(new Font(g.getFont().getFontName(), g.getFont().getStyle(), 24));
				String msg = "GAME OVER!";
				FontMetrics metrics = g.getFontMetrics();
				int width = metrics.stringWidth(msg);
				int height = metrics.getHeight();
				g.drawString(msg, (this.getWidth() - width)/2, (this.getHeight() - height)/2);
			}
			else
			{
				g.drawImage(imgGameOver, (this.getWidth() - imgGameOver.getWidth())/2, (this.getHeight() - imgGameOver.getHeight())/2, null);
			}
			
			// show the player's score
			g.setColor(Color.white);
			g.setFont(new Font(g.getFont().getFontName(), g.getFont().getStyle(), 14));
			String msg = "Level " + Scoreboard.getScoreboard().getLevel() + ", Score: " + Scoreboard.getScoreboard().getScore();
			FontMetrics metrics = g.getFontMetrics();
			int swidth = metrics.stringWidth(msg);
			int sheight = metrics.getHeight();
			g.drawString(msg, (this.getWidth() - swidth)/2, (this.getHeight() - 64));
		}
		else if(gameState == CollapsingBricksGame.GameState.PAUSED)
		{
			/*
			 * Simply draw a black background with a centered text that states
			 * "PAUSED". Use the anti-aliased text image, if possible. Otherwise
			 * just write it using a system font.
			 */
			
			g.setColor(Color.black);
			g.fillRect(0, 0, this.getWidth(), this.getHeight());
			
			if(imgGameLogo == null)
			{
				// can't find logo...
			}
			else
			{
				g.drawImage(imgGameLogo, (this.getWidth() - imgGameLogo.getWidth())/2, 0, null);
			}
			
			if(imgPaused == null) // text version
			{
				g.setColor(Color.white);
				g.setFont(new Font(g.getFont().getFontName(), g.getFont().getStyle(), 24));
				String msg = "PAUSED";
				FontMetrics metrics = g.getFontMetrics();
				int width = metrics.stringWidth(msg);
				int height = metrics.getHeight();
				g.drawString(msg, (this.getWidth() - width)/2, (this.getHeight() - height)/2);
			}
			else
			{
				g.drawImage(imgPaused, (this.getWidth() - imgPaused.getWidth())/2, (this.getHeight() - imgPaused.getHeight())/2, null);
			}
			
			// show the player's score
			g.setColor(Color.white);
			g.setFont(new Font(g.getFont().getFontName(), g.getFont().getStyle(), 14));
			String msg = "Level " + Scoreboard.getScoreboard().getLevel() + ", Score: " + Scoreboard.getScoreboard().getScore();
			FontMetrics metrics = g.getFontMetrics();
			int swidth = metrics.stringWidth(msg);
			int sheight = metrics.getHeight();
			g.drawString(msg, (this.getWidth() - swidth)/2, (this.getHeight() - 64));
		}
		else if(gameState == CollapsingBricksGame.GameState.PLAYING)
		{
			/*
			 * Draw a black background, and (if enabled) the grid. Then draw
			 * all of the bricks in the bucket.
			 */
			
			// world to screen coordinates
			calculateNDToScreen();
			g2.transform(worldToND);
			g2.transform(ndToScreen);
			
			// paint the background
			drawBackground(g2);
			
			// draw all objects in the bucket
			Iterator world = theBucket.getIterator();
			while(world.hasNext())
			{
				((Brick)world.next()).draw(g2);
			}
		}
		
		// restore the transform
		g2.setTransform(saveAT);
		g2.setColor(saveColor);
	}
	
	private void drawBackground(Graphics2D g)
	{
		/*
		 * Draws a black background and (if enabled), the grid.
		 */
		
		// save transform
		AffineTransform saveAT = g.getTransform();
		Color saveColor = g.getColor();
		
		// this is okay if we're using whole numbers for the viewing window boundaries
		int viewWidth = (int)CollapsingBricksGame.getCollapsingBricksGame().getViewingWindowRight();
		int viewHeight = (int)CollapsingBricksGame.getCollapsingBricksGame().getViewingWindowTop();
		
		g.setColor(Color.black);
		g.fillRect(0, 0, viewWidth, viewHeight);
		
		if(gridVisible)
		{			
			g.setColor(new Color(32, 32, 32));
			Stroke saveStroke = g.getStroke();
			
			// draw lines for columns
			for(int i = 0; i < Bucket.BUCKET_WIDTH; i++)
			{
				g.drawLine(i * Brick.BRICK_SIZE, 0, i * Brick.BRICK_SIZE, viewHeight);
			}
			
			// draw lines for rows
			for(int i = 0; i < Bucket.BUCKET_HEIGHT; i++)
			{
				g.drawLine(0, i * Brick.BRICK_SIZE, viewWidth, i * Brick.BRICK_SIZE);
			}
			
			g.setStroke(saveStroke);
		}
		
		// restore transform
		g.setTransform(saveAT);
		g.setColor(saveColor);
	}
}
